package com.cj.common.web.struts2;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cj.common.entity.IdEntity;
import com.cj.common.orm.Page;
import com.cj.common.orm.PropertyFilter;
import com.cj.common.orm.hibernate.EntityManager;
import com.cj.common.orm.hibernate.HibernateWebUtils;
import com.cj.common.utils.ReflectionUtils;
import com.cj.sys.entity.security.Authority;
import com.cj.sys.entity.security.User;
import com.cj.sys.service.ServiceException;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;

/**
 * Struts2中典型CRUD Action的抽象基类.
 * 
 * 主要定义了对Preparable,ModelDriven接口的使用,以及CRUD函数和返回值的命名.
 * 
 * @param <T>
 *            CRUDAction所管理的对象类型.
 * 
 * @author calvin
 */
@SuppressWarnings("serial")
public abstract class CRUDActionSupport<T extends IdEntity> extends BaseActionSupport
		implements
		ModelDriven<T>, Preparable {
	protected Long id;
	protected Page<T> page = new Page<T>(25);
	protected T entity;

	/**
	 * 进行增删改操作后,以redirect方式重新打开action默认页的result名.
	 */
	public static String DETAIL = "detail";
	public static String SEARCH = "search";
	
	protected List<Long> idKeys;
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * Action函数,默认action函数，默认指向list函数.
	 */
	@Override
	public String execute() {
		try {
			return list();
		} catch (Exception e) {
			setErrMessage(e.getMessage(), e);
			return ERROR;
		}
	}
	
	/**
	 * EntityManager.
	 */	
	public abstract EntityManager getEntityManager();

	// CRUD函数 //

	/**
	 * Action函数,显示Entity列表. 建议return SUCCESS.
	 */
	public String list(){
		try {
			HttpServletRequest request = Struts2Utils.getRequest();
			List<PropertyFilter> filters = HibernateWebUtils.buildPropertyFilters(request);
			page = getEntityManager().search(page, filters);
			return SUCCESS;
		} catch (Exception e) {
			setErrMessage(e.getMessage(),e);
			return ERROR;
		}
	}

	/**
	 * Action函数,新增或修改Entity. 建议return RELOAD.
	 */
	public String save(){
		try {
			getEntityManager().save(entity);
			addActionMessage("保存成功");
			return list();			
		} catch (Exception e) {
			setErrMessage(e.getMessage(), e);
			return ERROR;
		}
	}

	/**
	 * Action函数,删除Entity. 建议return RELOAD.
	 */
	public String delete(){
		try {
			getEntityManager().delete(getId());
			addActionMessage("删除成功");
			return list();
		} catch (ServiceException e) {
			setErrMessage(e.getMessage(), e);
			return ERROR;
		}
	}
	/**
	 * 【删除】
	 */
	public String remove() {
		try {
			if (getIdKeys() == null)
				return list();
			for (Long key : getIdKeys()) {
				getEntityManager().delete(key);
			}
			return list();
		} catch (ServiceException e) {
			logger.error(e.getMessage(), e);
			addActionMessage(e.getMessage());
			return "error";
		}
	}

	public String detail(){
		try {
			return DETAIL;
		} catch (Exception e) {
			setErrMessage(e.getMessage(), e);
			return ERROR;
		}
	}
	@Override
	public String input() {
		try {
			return INPUT;
		} catch (Exception e) {
			setErrMessage(e.getMessage(), e);
			return ERROR;
		}
	}


	// Preparable函数 //

	/**
	 * 实现空的prepare()函数,屏蔽所有Action函数公共的二次绑定.
	 */
	public void prepare() throws Exception {
	}

	/**
	 * 在save()前执行二次绑定.
	 */
	
	public void prepareSave() throws Exception {
		prepareModel();
	}
	
	public void prepareDetail() throws Exception {
		prepareModel();
	}
	
	/**
	 * 在input()前执行二次绑定.
	 */
	public void prepareInput() throws Exception {
		prepareModel();
	}

	/**
	 * 等同于prepare()的内部函数,供prepardMethodName()函数调用.
	 * 最好覆盖直接new出来
	 */
	protected void prepareModel() throws Exception{
		if (id != null) {
			entity = (T)getEntityManager().get(id);
		} else {
			entity = (T)ReflectionUtils.getSuperClassGenricType(getClass()).newInstance();
		}
	}



	public List<Long> getIdKeys() {
		return idKeys;
	}

	public void setIdKeys(List<Long> idKeys) {
		this.idKeys = idKeys;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Page<T> getPage() {
		return page;
	}

	public void setPage(Page<T> page) {
		this.page = page;
	}
	public T getModel() {
		return entity;
	}
}
